﻿using System;
using System.Reflection;
using System.Windows;
using System.Windows.Input;
using XEvolve.Core.Runtime;

namespace XEvolve.Presentation.Input.Internal
{
    class WindowsInputICommandSourceAdapterFactory : IAdapterFactory
    {
        public object CreateAdapter(object adaptee, Type adapterType)
        {
            return new WindowsInputICommandSourceAdapter((System.Windows.Input.ICommandSource)adaptee);
        }

        private static bool CanWrite(object adaptee)
        {
            var type = adaptee.GetType();
            return type.GetProperty("CommandParameter").CanWrite && type.GetProperty("Command").CanWrite;
        }

        public bool CanCreateAdapter(object adaptee, Type adapterType)
        {
            return adapterType == typeof(ICommandSource) && adaptee is System.Windows.Input.ICommandSource && CanWrite(adaptee);
        }
        
        class WindowsInputICommandSourceAdapter : ICommandSource
        {
            private readonly System.Windows.Input.ICommandSource source;
            private readonly MethodInfo commandSetter;
            private readonly MethodInfo commandParameterSetter;
            

            public WindowsInputICommandSourceAdapter(System.Windows.Input.ICommandSource source)
            {
                this.source = source;
                commandSetter = source.GetType().GetProperty("Command").GetSetMethod(true);
                commandParameterSetter = source.GetType().GetProperty("CommandParameter").GetSetMethod(true);                
            }

            public ICommand Command
            {
                get { return source.Command; }
            }

            public object CommandParameter
            {
                get { return source.CommandParameter; }                
            }

            public IInputElement CommandTarget
            {
                get { return source.CommandTarget; }
            }

            public void SetCommand(ICommand command)
            {
                commandSetter.Invoke(source, new[] {command});
            }

            public void SetCommandParameter(object value)
            {
                commandParameterSetter.Invoke(source, new []{value});
            }
        }
    }    
}